package com.zx.crowdfunding.util;

import java.io.InputStream;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

import javax.servlet.http.HttpServletRequest;

import org.apache.http.HttpResponse;
import org.apache.http.StatusLine;

import com.aliyun.api.gateway.demo.util.HttpUtils;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.common.comm.ResponseMessage;
import com.aliyun.oss.model.PutObjectResult;
import com.zx.crowdfunding.constant.CrowdFundingConstant;

/**
 * 通用工具方法类
 * @author 郑雪
 * @date 2021-12-08
 */
public class CrowdFundingUtil {
	
	/**
	 * 上传文件到OSS服务器（调用第三方OSS接口）
	 * @param endPoint 			访问OSS的域名
	 * @param bucketName 		存储Object的存储空间名称
	 * @param bucketDomain 		存储空间访问域名
	 * @param accessKeyId 		OSS的访问密钥AccessKeyId
	 * @param accessKeySecret	OSS的访问密钥AccessKeySecret
	 * @param inputStream 		上传文件的输入流
	 * @param originalFileName 	上传文件的原始文件名
	 * @return 包含上传结果以及上传的文件在OSS上的访问路径
	 */
	public static ResultEntity<String> uploadFileToOss(
				String endPoint,
				String bucketName,
				String bucketDomain,
				String accessKeyId,
				String accessKeySecret,
				InputStream inputStream,
				String originalFileName
			){
		
		// 生成OSSClient
        OSS ossClient = new OSSClientBuilder().build(endPoint, accessKeyId, accessKeySecret);

        // 生成上传文件的目录
        String folderName = new SimpleDateFormat("yyyyMMdd").format(new Date());
        
        // 生成上传文件在OSS服务器上保存时的文件名
        // 原始文件名：girl.jpg
        // 生成文件名：uuid.jpg
        // 使用UUID生成文件主体名称
        String fileMainName = UUID.randomUUID().toString().replace("-", "");
        
        // 从原始文件名中获取文件扩展名
 		String extensionName = originalFileName.substring(originalFileName.lastIndexOf("."));
        
 		// 使用目录、文件主体名称、文件扩展名称拼接得到对象名称
		String objectName = folderName + "/" + fileMainName + extensionName;
 			
        try {

        	// 调用OSS客户端对象的方法上传文件并获取响应结果数据
			PutObjectResult putObjectResult = ossClient.putObject(bucketName, objectName, inputStream);
        	
			// 从响应结果中获取具体响应消息
			ResponseMessage responseMessage = putObjectResult.getResponse();
			
			// 根据响应状态码判断请求是否成功
			if(responseMessage == null) {
				
				// 拼接访问刚刚上传的文件的路径
				String ossFileAccessPath = bucketDomain + "/" + objectName;
				
				System.out.println("Object：" + objectName + "存入OSS成功。");
				
				// 当前方法返回成功
				return ResultEntity.successWithData(ossFileAccessPath);
			} else {
				// 获取响应状态码
				int statusCode = responseMessage.getStatusCode();
				
				// 如果请求没有成功，获取错误消息
				String errorMessage = responseMessage.getErrorResponseAsString();
				
				// 当前方法返回失败
				return ResultEntity.failed("当前响应状态码="+statusCode+" 错误消息="+errorMessage);
			}

        } catch (Exception e) {
        	e.printStackTrace();
        	
        	// 当前方法返回失败
			return ResultEntity.failed(e.getMessage());
        } finally {
        	
        	if(ossClient != null) {
				
				// 关闭OSSClient。
				ossClient.shutdown();
			}
        }

	}
	
	/**
	 * 发送短信验证码（调用第三方短信接口）
	 * @param host			短信接口调用的URL地址
	 * @param path			具体发送短信功能的地址
	 * @param method		请求方式
	 * @param phoneNum		接收验证码的手机号
	 * @param appCode		用来调用第三方短信API的AppCode
	 * @param smsSignId 	签名编号
	 * @param templateId	模板编号
	 * @return 返回调用结果是否成功
	 * 		成功：返回验证码
	 * 		失败：返回失败消息
	 * 		状态码: 200 正常；400 URL无效；401 appCode错误； 403 次数用完； 500 API网管错误
	 */
	public static ResultEntity<String> sendCodeByShortMessage(
				String host,
				String path,
				String method,
				String phoneNum,
				String appCode,
				String smsSignId,
				String templateId
			){
		
	    Map<String, String> headers = new HashMap<String, String>();
	    
	    // 最后在header中的格式(中间是英文空格)为Authorization:APPCODE 83359fd73fe94948385f570e3c139105
	    headers.put("Authorization", "APPCODE " + appCode);
	    
	    // 封装其他参数
	    Map<String, String> querys = new HashMap<String, String>();
	    
	    // 接收短信的手机号
	    querys.put("mobile", phoneNum);
	    
	    // 生成验证码
	    StringBuilder builder = new StringBuilder();
	    for (int i = 0; i < 4; i++) {
			int random = (int) (Math.random() * 10);
	    	builder.append(random);
		}
	    String code = builder.toString();
	    
	    // 要发送的验证码，也就是模板中会变化的部分
	    querys.put("param", "**code**:" + code + ",**minute**:5");
	    
	    // 签名编号
	    querys.put("smsSignId", smsSignId);
	    
	    // 模板编号
	    querys.put("templateId", templateId);
	    Map<String, String> bodys = new HashMap<String, String>();

	    try {
	    	HttpResponse response = HttpUtils.doPost(host, path, method, headers, querys, bodys);
	    	
	    	StatusLine statusLine = response.getStatusLine();
	    	
	    	// 状态码: 200 正常；400 URL无效；401 appCode错误； 403 次数用完； 500 API网管错误
	    	int statusCode = statusLine.getStatusCode();
	    	
	    	String reasonPhrase = statusLine.getReasonPhrase();
	    	
	    	System.out.println("statusCode="+statusCode);
	    	System.out.println("reasonPhrase="+reasonPhrase);
	    	System.out.println(response.toString());
	    	//获取response的body
	    	//System.out.println(EntityUtils.toString(response.getEntity()))

			if(statusCode == 200) {
				
				// 操作成功，把生成的验证码返回
				return ResultEntity.successWithData(code);
			}
			
			return ResultEntity.failed(reasonPhrase);
	    } catch (Exception e) {
	    	e.printStackTrace();
	    	return ResultEntity.failed(e.getMessage());
	    }
		
	}
	
	/**
	 * 字符串MD5加密
	 * @param source 要加密的字符串
	 * @return 加密后的字符串
	 */
	public static String md5(String source){
		
		//1.判断source是否有效
		if(source == null || source.length() == 0){
			
			//2.如果不是有效的字符串抛出异常
			throw new RuntimeException(CrowdFundingConstant.MESSAGE_STRING_INVALIDATE);
		}
		
		try {
			//3.获取MessageDigest对象
			String algorithm = "md5";
			
			//jdk提供的加密对象，传入加密算法的名称即可
			MessageDigest messageDigest = MessageDigest.getInstance(algorithm);
			
			//4.获取明文字符串对应的字节数组
			byte[] input = source.getBytes();
			
			//5.执行加密
			byte[] output = messageDigest.digest(input);
			
			//6.创建BigInteger对象
			int signum = 1;
			BigInteger bigInteger = new BigInteger(signum, output);
			
			//7.按照16进制将BigInteger的值转换为字符串
			int radix = 16; 
			String encoded = bigInteger.toString(radix);
			
			//8.返回加密后的字符串，并转换为大写
			return encoded.toUpperCase();
			
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
		
		return null;
	}
	
	/**
	 * 判断当前请求是否为Ajax请求
	 * @param request 请求对象
	 * @return 
	 * 		true：当前请求是Ajax请求<br>
	 * 		false：当前请求不是Ajax请求
	 */
	public static boolean judgeRequestType(HttpServletRequest request){
		
		//1.获取请求消息头
		String acceptHeader = request.getHeader("Accept");
		String xRequestHeader = request.getHeader("X-Requested-With");
		
		//2.判断
		return (acceptHeader != null && acceptHeader.contains("application/json"))
				
				|| 
				
				(xRequestHeader != null && xRequestHeader.equals("XMLHttpRequest"));
	}

}
